#include "stdafx.h"

#include "CamWrapper.h"
#include "VideoCapture_AvtGigE.h"
#include "VideoCapture_AvtUniAPI.h"
#include "VideoCapture_OpenCvHighGui.h"

CamWrapper::CamWrapper() {
	this->camInterface = CAM_INTERFACE_TYPE_END;
	this->camUniqueId = 0;
	this->opened = false;
	this->targetCam = NULL;
	this->verbose = true;
	this->initialised = false;
	this->rgbImage = NULL;
}

CamWrapper::CamWrapper(CAM_INTERFACE_TYPE iface) {
	this->camInterface = iface;
	this->camUniqueId = 0;
	this->opened = false;
	this->targetCam = NULL;
	this->verbose = true;
	this->initialised = false;
	this->rgbImage = NULL;
}

CamWrapper::~CamWrapper() {
	this->text(std::string("CamWrapper::~CamWrapper() called.\n"));
	if(this->isOpened()) {
		this->closeCam();
	}
	if(this->isInitialised()) {
		this->releaseInterface();
	}
	if(this->rgbImage!=NULL) {
		cvReleaseImage(&this->rgbImage);
	}
}

bool CamWrapper::initInterface() {
	return this->initInterface(this->camInterface);
}

bool CamWrapper::initInterface(CAM_INTERFACE_TYPE iface) {
	if(this->isInitialised()) {
        this->text(std::string("CamWrapper::initInterface(): interface is already initialised, forced re-initialising...\n"));
		this->closeCam();
		this->releaseInterface();
    }
    switch(iface) {
    case CAM_INTERFACE_TYPE_HIGH_GUI :
#ifndef NO_HIGHGUI_CAM
#endif
		this->targetCam = new OpenCvHighGui();
        break;
    case CAM_INTERFACE_TYPE_AVT_UNIAPI :
#ifndef NO_AVT_UNIAPI
        this->targetCam = new AvtUniAPI();
		this->targetCam->initCam();
#endif
        break;
    case CAM_INTERFACE_TYPE_AVT_GIGE :
#ifndef NO_AVT_GIGE
        this->targetCam = new AvtGigE();
#endif
        break;
    case CAM_INTERFACE_TYPE_IMAGING_SOURCE :
#ifndef NO_IMAGING_SOURCE
#endif
        break;
    default : // no suitable interface found
        this->camInterface = iface;
        this->initialised = false;
        return false;
    }
    this->camInterface = iface;
    this->initialised = true;
    return true;
}

IplImage* CamWrapper::grabRawImage() {
	return this->targetCam->grabRawImage();
//    switch(this->camInterface) {
//    case CAM_INTERFACE_TYPE_HIGH_GUI :
//#ifndef NO_HIGHGUI_CAM
//		return this->highGuiCam->grabRawImage();
//#endif
//        break;
//    case CAM_INTERFACE_TYPE_AVT_UNIAPI :
//#ifndef NO_AVT_UNIAPI
//        return this->avtUniApiCam->grabRawImage();
//#endif
//        break;
//    case CAM_INTERFACE_TYPE_AVT_GIGE :
//#ifndef NO_AVT_GIGE
//        return this->avtGigEcam->grabRawImage();
//#endif
//        break;
//    case CAM_INTERFACE_TYPE_IMAGING_SOURCE :
//#ifndef NO_IMAGING_SOURCE
//#endif
//        break;
//    default : // no suitable interface found
//        return NULL;
//
//    }
//	return NULL; // for compiler warning
}

bool CamWrapper::openCam(unsigned long camId) {
	if(!this->isInitialised()) {
        this->text(std::string("CamWrapper::openCam(): interface is not initialised yet\n"));
        return false;
    }
	if(this->isOpened()) {
        this->text(std::string("CamWrapper::openCam(): camera is already opened\n"));
        return false;
    }
        if(!this->targetCam->openCam((int) camId)) {
            this->text("CamWrapper::openCam(): cam open failed.\n",true);
            return false;
        }
//    switch(this->camInterface) {
//    case CAM_INTERFACE_TYPE_HIGH_GUI :
//#ifndef NO_HIGHGUI_CAM
//        if(!this->highGuiCam->openCam((int) camId)) {
//            this->text("CamWrapper::openCam(): HighGUI cam open failed.\n",true);
//            return false;
//        }
//#endif
//        break;
//    case CAM_INTERFACE_TYPE_AVT_UNIAPI :
//#ifndef NO_AVT_UNIAPI
//        this->avtUniApiCam->selectCamera((unsigned int) camId);
//        if(!this->avtUniApiCam->capture_init()) {
//                this->text("CamWrapper::openCam(): AvtUniAPIcam open failed.\n",true);
//                return false;
//        }
//#endif
//        break;
//    case CAM_INTERFACE_TYPE_AVT_GIGE :
//#ifndef NO_AVT_GIGE
//        if(!this->avtGigEcam->openCam(camId)) {
//                this->text("CamWrapper::openCam(): Avt GigE camera open failed. \n",true);
//                return false;
//        }
//#endif
//        break;
//    case CAM_INTERFACE_TYPE_IMAGING_SOURCE :
//#ifndef NO_IMAGING_SOURCE
//#endif
//        break;
//    default : // no suitable interface found
//        return false;
//
//    }
    this->text(std::string("CamWrapper::openCam(): success\n"));
    this->opened = true;
    return true;
}

bool CamWrapper::closeCam() {
    if(!this->isOpened()) {
        this->text(std::string("CamWrapper::openCam(): camera is not opened\n"));
        return true;
    }
	this->targetCam->closeCam();
//    switch(this->camInterface) {
//    case CAM_INTERFACE_TYPE_HIGH_GUI :
//#ifndef NO_HIGHGUI_CAM
//		this->highGuiCam->closeCam();
//#endif
//        break;
//    case CAM_INTERFACE_TYPE_AVT_UNIAPI :
//#ifndef NO_AVT_UNIAPI
//        this->avtUniApiCam->capture_exit();
//#endif
//        break;
//    case CAM_INTERFACE_TYPE_AVT_GIGE :
//#ifndef NO_AVT_GIGE
//        this->avtGigEcam->closeCam();
//#endif
//        break;
//    case CAM_INTERFACE_TYPE_IMAGING_SOURCE :
//#ifndef NO_IMAGING_SOURCE
//#endif
//        break;
//    default : // no suitable interface found
//        return false;
//
//    }
this->opened = false;
this->initialised = false;
this->text(std::string("CamWrapper::closeCam(): success\n"));
        return true;
}

bool CamWrapper::releaseInterface() {
	if(!this->isInitialised()) {
		this->text(std::string("CamWrapper::releaseInterface(): interface is not initialised yet\n"));
		return false;
	}
	if(this->isOpened()) {
        this->closeCam(); // Close cam first before release interface, try release interface regardless of outcome
    }
	delete this->targetCam;
	this->targetCam = NULL;
   //     switch(this->camInterface) {
   //     case CAM_INTERFACE_TYPE_HIGH_GUI :
   // #ifndef NO_HIGHGUI_CAM
			//delete this->highGuiCam;
   //         this->highGuiCam = NULL;
   // #endif
   //         break;
   //     case CAM_INTERFACE_TYPE_AVT_UNIAPI :
   // #ifndef NO_AVT_UNIAPI
   //         delete this->avtUniApiCam;
   //         this->avtUniApiCam = NULL;
   // #endif
   //         break;
   //     case CAM_INTERFACE_TYPE_AVT_GIGE :
   // #ifndef NO_AVT_GIGE
   //         delete this->avtGigEcam;
   //         this->avtGigEcam = NULL;
   // #endif
   //         break;
   //     case CAM_INTERFACE_TYPE_IMAGING_SOURCE :
   // #ifndef NO_IMAGING_SOURCE
   // #endif
   //         break;
   //     default : // no suitable interface found, never should reached here
   //         this->text(std::string("CamWrapper::releaseInterface(): never should reached default:\n"),true);
   //         return false;
   //     }
    this->initialised = false;
    this->text(std::string("CamWrapper::releaseInterface(): success\n"));
        return true;
}

bool CamWrapper::probeCam(unsigned int &numFound) {
	numFound = this->targetCam->probeCam();
	if(numFound<0) return false;
	//switch(this->camInterface) {
 //       case CAM_INTERFACE_TYPE_HIGH_GUI :
 //   #ifndef NO_HIGHGUI_CAM

 //           this->highGuiCam = NULL;
 //   #endif
 //           break;
 //       case CAM_INTERFACE_TYPE_AVT_UNIAPI :
 //   #ifndef NO_AVT_UNIAPI
 //           delete this->avtUniApiCam;
 //           this->avtUniApiCam = NULL;
 //   #endif
 //           break;
 //       case CAM_INTERFACE_TYPE_AVT_GIGE :
 //   #ifndef NO_AVT_GIGE
 //           delete this->avtGigEcam;
 //           this->avtGigEcam = NULL;
 //   #endif
 //           break;
 //       case CAM_INTERFACE_TYPE_IMAGING_SOURCE :
 //   #ifndef NO_IMAGING_SOURCE
 //   #endif
 //           break;
	//default:
	//	return false;
	//}
	return true;
}

bool CamWrapper::getCamProperties(unsigned long propId, unsigned long &value) {
	switch(this->camInterface) {
	case CAM_INTERFACE_TYPE_AVT_UNIAPI :
#ifndef NO_AVT_UNIAPI
		return this->targetCam->getCamProperties(propId,value);
#endif
		break;
	}
	return false;
}

bool CamWrapper::setCamProperties(unsigned long propId, unsigned long value) {
	switch(this->camInterface) {
	case CAM_INTERFACE_TYPE_AVT_UNIAPI :
#ifndef NO_AVT_UNIAPI
		return this->targetCam->setCamProperties(propId,value);
#endif
		break;
	}
	return false;
}

bool CamWrapper::getCamProperties(unsigned long propId, double &value) {
	switch(this->camInterface) {
	case CAM_INTERFACE_TYPE_HIGH_GUI :
#ifndef NO_AVT_UNIAPI
		return this->targetCam->getCamProperties(propId,value);
#endif
		break;
	}
	return false;
}

bool CamWrapper::setCamProperties(unsigned long propId, double value){
	switch(this->camInterface) {
	case CAM_INTERFACE_TYPE_HIGH_GUI :
#ifndef NO_HIGHGUI_CAM
		return this->targetCam->setCamProperties(propId,value);
#endif
		break;
	}
	return false;
}

bool CamWrapper::getCamProperties(char *propId, unsigned long &value){
	switch(this->camInterface) {
	case CAM_INTERFACE_TYPE_AVT_GIGE :
#ifndef NO_AVT_GIGE
		return this->targetCam->getCamProperties(propId,value);
#endif
		break;
	}
	return false;
}

bool CamWrapper::setCamProperties(char *propId, unsigned long value){
	switch(this->camInterface) {
	case CAM_INTERFACE_TYPE_AVT_GIGE :
#ifndef NO_AVT_GIGE
		return this->targetCam->setCamProperties(propId,value);
#endif
		break;
	}
	return false;
}

bool CamWrapper::setImageSize(unsigned int width, unsigned int height, unsigned int bytesPerChannel, unsigned int channels) {
	return this->targetCam->setImageSize(width,height,bytesPerChannel,channels);
}

bool CamWrapper::setVerbose(bool isVerbose) {
	this->verbose = isVerbose;
	return true;
}

bool CamWrapper::isInitialised() { return this->initialised; }

bool CamWrapper::isOpened() { return this->opened; }

unsigned long CamWrapper::getCurrentCamID() { return this->camUniqueId; }

void CamWrapper::text(std::string message, bool error) {
	if(verbose)	{
		if(error) {
		std::cerr<<message;
	} else {
		std::cout<<message;
	}
	}
}

bool CamWrapper::getCamId(int index, unsigned long &camId, std::string *camName) {
	return this->targetCam->getCamId(index, camId,camName);
}

void CamWrapper::deInteraceImage(char *dataSource, char *dataDist, int width, int height, int srcWidthStep, int dstWidthStep) {
	int B = 0;
	int G = 1;
	int R = 2;
	int c;
	uchar *srcPtr = (uchar*) dataSource;
	uchar *dstPtr = (uchar*) dataDist;
	int interaceStep = width*(height/2);
	uchar *CFAptrG, *CFAptrC, *CFAptrY, *CFAptrM;
	int srcLineFeed = srcWidthStep - width;
	int dstLineFeed = dstWidthStep - (width * 3);
	int srcLine = 0;
	bool evenLine = true;
	bool quadLine = false;
	bool oddCol;// = false;
	int Ri, Bi;
	for (int y = 0; y<height; y++) {
		oddCol = false;
		if(evenLine) {
			srcPtr = (uchar*) dataSource + srcWidthStep * srcLine;
			evenLine = false;
		} else {
			srcPtr = (uchar*) dataSource + srcWidthStep * srcLine + interaceStep;
			srcLine++;
			evenLine = true;
		}
		for(int x = 0; x<width; ++x) {
		//dstPtr[G] = *srcPtr; dstPtr[B] = *srcPtr; dstPtr[R] = *srcPtr;
		if(evenLine && oddCol) { // actually processing odd line now 1,3,5,7... 
			if(quadLine) {
				CFAptrG = srcPtr;
				CFAptrM = srcPtr-1;
				quadLine = false;
			} else {
				CFAptrG = srcPtr-1;
				CFAptrM = srcPtr;
				quadLine = true;
			}
			CFAptrY = srcPtr - srcWidthStep;
			CFAptrC = CFAptrY -1;
			dstPtr[G] = CFAptrG[0];
			Ri = (int) CFAptrM[0] - (int) CFAptrG[0];
			dstPtr[R] = Ri > 0 ? (uchar) Ri : 0;
			Bi = (int) CFAptrC[0] - (int) CFAptrG[0];
			dstPtr[B] = Bi > 0 ? (uchar) Bi : 0;
			{ // filling other pixels
				dstPtr[-3] = dstPtr[B];
				dstPtr[-2] = dstPtr[G];
				dstPtr[-1] = dstPtr[R];
				dstPtr[-dstWidthStep] = dstPtr[B];
				dstPtr[-dstWidthStep+1] = dstPtr[G];
				dstPtr[-dstWidthStep+2] = dstPtr[R];
				dstPtr[-dstWidthStep-3] = dstPtr[B];
				dstPtr[-dstWidthStep+1-3] = dstPtr[G];
				dstPtr[-dstWidthStep+2-3] = dstPtr[R];
			}
		}
		if(oddCol) oddCol = false; else oddCol = true;
		dstPtr+=3;
		++srcPtr;
	}
		//srcPtr += srcLineFeed;
		dstPtr += dstLineFeed;
	}
}

IplImage* CamWrapper::grabDemosaicingImage(DEMOSAICING_TYPE demosaicingMethod, CFA_TYPE cfaType) {
	IplImage *rawImage = this->grabRawImage();
	IplImage *returnImage;
	switch(this->camInterface) {
	case CAM_INTERFACE_TYPE_HIGH_GUI: // as it is
		returnImage = rawImage;
		break;
	case CAM_INTERFACE_TYPE_AVT_UNIAPI:
	case CAM_INTERFACE_TYPE_AVT_GIGE:
		if(this->rgbImage!=NULL) {
			cvReleaseImage(&rgbImage);
		}
		rgbImage = cvCreateImage(cvSize(rawImage->width,rawImage->height),IPL_DEPTH_8U, CH_COLOR);
		if(this->targetCam->interacedCapture) {
			this->deInteraceImage(rawImage->imageData,rgbImage->imageData,rawImage->width,rawImage->height,rawImage->widthStep,rgbImage->widthStep);
		} else {
			cvCvtColor(rawImage, this->rgbImage,  CV_BayerBG2BGR);

		}
		returnImage = this->rgbImage;
		break;
	}
	return returnImage;
}
